/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package org.academik.controller;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Iterator;
import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import javax.faces.context.FacesContext;
import javax.faces.model.SelectItem;
import org.academik.model.Nivel;
import org.academik.util.FacesUtil;
import org.academik.util.HibernateUtil;
import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.criterion.Order;

/**
 *
 * @author Javier
 */
@ManagedBean(name = "nivelBean")
@ViewScoped
public class NivelBean extends AbstractViewScopedBean implements Serializable {

    /** Declaracion de Variables */
    private Nivel nivel;
    private ArrayList<Nivel> niveles;
    private Nivel selectedNivel;
    private boolean cargarNivel;

    /** Creates a new instance of NivelBean */
    public NivelBean() {
        this.nuevo();
    }

    @Override
    public void crear() {
        Session session = HibernateUtil.getSessionFactory().openSession();
        Transaction tx = null;
        try {
            tx = (Transaction) session.beginTransaction();
            if (this.cargarNivel == false) /* Si es nuevo registro que genere el correlativo sino solo que modifique */ {
                this.nivel.setNuNivel(this.generarCorrelativo(session));
            }
            session.saveOrUpdate(this.nivel);
            session.flush();
            session.clear();
            tx.commit();
            this.nuevo();
            FacesContext.getCurrentInstance().addMessage(null,
                    new FacesMessage(FacesMessage.SEVERITY_INFO, "Información:", "El nivel se creo satisfactoriamente"));
        } catch (HibernateException e) {
            tx.rollback();
            FacesUtil.hibernateException(e);
        } finally {
            session.close();
        }
    }

    @Override
    public void eliminar() {
        Session session = HibernateUtil.getSessionFactory().openSession();
        Transaction tx = null;
        Nivel s = (Nivel) session.load(Nivel.class, this.selectedNivel.getIdNivel());
        byte numeroNivel = this.selectedNivel.getNuNivel();
        try {
            tx = (Transaction) session.beginTransaction();
            session.delete(s);
            session.flush();
            session.clear();
            tx.commit();
            this.reordenar(numeroNivel);
            this.nuevo();
            FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_INFO, "Información:", "Registro eliminado satisfactoriamente"));
        } catch (HibernateException e) {
            tx.rollback();
            FacesUtil.hibernateException(e);
        } finally {
            session.close();
        }
    }

    @Override
    public void cargarOpciones() {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    @Override
    public void cargarOpciones(int id) {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    @Override
    public void buscar() {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    @Override
    public void modificar() {
        this.nivel = this.selectedNivel;
        this.cargarNivel = true;
    }

    @Override
    public void cargarResgistros() {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    @Override
    public void nuevo() {
        this.nivel = new Nivel();
        this.niveles = new ArrayList<Nivel>();
        this.selectedNivel = null;
        this.cargarNivel = false;
        this.populateNiveles();
    }

    /** Genera el numero del nivel*/
    public byte generarCorrelativo(Session session) {
        byte numero = 1;
        String sql = "SELECT MAX(n.nuNivel) FROM nivel n";
        Query query = session.createSQLQuery(sql);
        if (query.uniqueResult() != null) {
            numero = (byte) (((Byte) query.uniqueResult()).byteValue() + 1);
        }
        return numero;
    }

    /** Muestra los datos de la BD en la tabla*/
    public void populateNiveles() {
        Session session = HibernateUtil.getSessionFactory().openSession();
        Criteria cNivel = session.createCriteria(Nivel.class);
        cNivel.addOrder(Order.asc("nuNivel"));
        this.niveles = (ArrayList<Nivel>) cNivel.list();
        session.close();
    }

    /** Reordenar los registros cuando se elimine uno*/
    public void reordenar(byte nivelEliminado) {
        Session session = HibernateUtil.getSessionFactory().openSession();
        Transaction tx = null;
        String sql = "";
        try {
            tx = (Transaction) session.beginTransaction();
            sql = "UPDATE nivel n "
                    + "SET n.nuNivel = n.nuNivel - 1 "
                    + "WHERE n.nuNivel > :numero";
            session.createSQLQuery(sql).setParameter("numero", nivelEliminado).executeUpdate();
            session.flush();
            session.clear();
            tx.commit();
            FacesContext.getCurrentInstance().addMessage(null,
                    new FacesMessage(FacesMessage.SEVERITY_INFO,
                    "Informacion:", "Los niveles fueron reordenados"));
        } catch (HibernateException e) {
            tx.rollback();
            FacesUtil.hibernateException(e);
        } finally {
            session.close();
        }
    }

    /** Subir el nivel (pasar de 2 a 3 por ejemplo)*/
    public void subir() {
        Session session = HibernateUtil.getSessionFactory().openSession();
        Nivel tempNivel = this.selectedNivel;
        byte numeroNivel = this.selectedNivel.getNuNivel();
        byte max = (Byte) numeroNivel;
        String sql = "SELECT MAX(n.nuNivel) FROM nivel n";
        Query query = session.createSQLQuery(sql);
        if (query.uniqueResult() != null) {
            max = ((Byte) query.uniqueResult()).byteValue();
        }
        if (numeroNivel < max) {
            Transaction tx = null;
            try {
                tx = (Transaction) session.beginTransaction();
                tempNivel.setNuNivel((byte) (numeroNivel + 1));
                session.saveOrUpdate(tempNivel);
                sql = "UPDATE nivel n "
                        + "SET n.nuNivel = n.nuNivel - 1 "
                        + "WHERE n.nuNivel = :numero";
                session.createSQLQuery(sql).setParameter("numero", numeroNivel + 1).executeUpdate();
                session.flush();
                session.clear();
                tx.commit();
                this.nuevo();
                FacesContext.getCurrentInstance().addMessage(null,
                        new FacesMessage(FacesMessage.SEVERITY_INFO,
                        "Informacion:", "El nivel '" + tempNivel.getVcNomNivel() + "' se movio a la posicion " + (numeroNivel + 1)));
            } catch (HibernateException e) {
                tx.rollback();
                FacesUtil.hibernateException(e);
            } finally {
                this.nuevo();
            }
        }
        session.close();
    }

    /** Bajar el nivel (pasar de 3 a 2 por ejemplo)*/
    public void bajar() {
        Session session = HibernateUtil.getSessionFactory().openSession();
        Nivel tempNivel = this.selectedNivel;
        byte numeroNivel = this.selectedNivel.getNuNivel();
        byte min = numeroNivel;
        String sql = "SELECT MIN(n.nuNivel) FROM nivel n";
        Query query = session.createSQLQuery(sql);
        if (query.uniqueResult() != null) {
            min = ((Byte) query.uniqueResult()).byteValue();
        }
        if (numeroNivel > min) {
            Transaction tx = null;
            try {
                tx = (Transaction) session.beginTransaction();
                tempNivel.setNuNivel((byte) (numeroNivel - 1));
                session.saveOrUpdate(tempNivel);
                sql = "UPDATE nivel n "
                        + "SET n.nuNivel = n.nuNivel + 1 "
                        + "WHERE n.nuNivel = :numero";
                session.createSQLQuery(sql).setParameter("numero", numeroNivel - 1).executeUpdate();
                session.flush();
                session.clear();
                tx.commit();
                this.nuevo();
                FacesContext.getCurrentInstance().addMessage(null,
                        new FacesMessage(FacesMessage.SEVERITY_INFO,
                        "Informacion:", "La nivel '" + tempNivel.getVcNomNivel() + "' se movio a la posicion " + (numeroNivel - 1)));
            } catch (HibernateException e) {
                tx.rollback();
                FacesUtil.hibernateException(e);
            } finally {
                this.nuevo();
            }
        }
        session.close();
    }

    /**
     * Carga la lista que sera mostrada en un cuadro de lista desplegable
     */
    public ArrayList<SelectItem> cargarNiveles() {
        ArrayList<SelectItem> lista = new ArrayList<SelectItem>();
        Session session = HibernateUtil.getSessionFactory().openSession();
        Criteria cSeccion = session.createCriteria(Nivel.class);
        cSeccion.addOrder(Order.asc("nuNivel"));
        Iterator iter = cSeccion.list().iterator();

        while (iter.hasNext()) {
            Nivel s = (Nivel) iter.next();
            lista.add(new SelectItem(s.getIdNivel(), s.getVcNomNivel(), ""));
        }
        session.close();
        return lista;
    }

    /** Getters & Setters*/
    public Nivel getNivel() {
        return nivel;
    }

    public void setNivel(Nivel nivel) {
        this.nivel = nivel;
    }

    public ArrayList<Nivel> getNiveles() {
        return niveles;
    }

    public void setNiveles(ArrayList<Nivel> niveles) {
        this.niveles = niveles;
    }

    public Nivel getSelectedNivel() {
        return selectedNivel;
    }

    public void setSelectedNivel(Nivel selectedNivel) {
        this.selectedNivel = selectedNivel;
    }
}
